home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
asmutil
/
a86v400.zip
/
A06A.DOC
< prev
next >
Wrap
Text File
|
1994-12-21
|
21KB
|
426 lines
CHAPTER 6 THE 86 INSTRUCTION SET
In this chapter we discuss in detail the instruction set
supported by both the A86 and A386 assemblers. To use any of the
32-bit registers, the extra segment regsiters FS and GS, or the
instructions marked with a "3", "4", or "5" in the instruction
list, you need my A386 assembler, available only if you register
both A86 and D86.
Effective Addresses
Most memory data accessing in the 86 family is accomplished via
the mechanism of the effective address. Wherever an effective
address specifier "eb", "ew" "ed", or "ev" appears in the list of
instructions, you may use a wide variety of actual operands in
that instruction. These include general registers, memory
variables, and a variety of indexed memory quantities.
GENERAL REGISTERS: Wherever an "ew" appears, you can use any of
the 16-bit registers AX,BX,CX,DX,SI,DI,SP, or BP. Wherever an
"eb" appears, you can use any of the 8-bit registers
AL,BL,CL,DL,AH,BH,CH, or DH. Whenever an "ed" occurs, you can
(on A386) use any of the 32-bit registers
EAX,EBX,ECX,EDX,ESI,EDI,EBP, or ESP. For A86, "ev" is the same
as "ew"; for A386, it means you can use either a 16-bit or a
32-bit register. For example, the "ADD ev,rv" form subsumes the
16-bit register-to-register adds; for example, ADD AX,BX; ADD
SI,BP; ADD SP,AX. On A386, this form also includes 32-bit
register-to-register adds; e.g., ADD EBX,ESI. At the machine
level the 16-vs.-32 distinction is made by an "operand override"
opcode byte, 66H, that A386 places before the instruction to
signal a switch from 16-bits to 32-bits.
MEMORY VARIABLES: Wherever an "eb", "ew", "ed", or "ev" appears,
you can use a memory variable of the indicated size: byte, word,
doubleword, or either-word-or-doubleword. Variables are
typically declared in the DATA segment, using a DD declaration
for a doubleword variable, a DW declaration for a word variable,
or a DB declaration for a byte variable. For example, you can
declare variables:
DATA_PTR DW ?
ESC_CHAR DB ?
Later, you can load or store these variables:
MOV ESC_CHAR,BL ; store the byte variable ESC_CHAR
MOV DATA_PTR,081 ; initialize DATA_PTR
MOV SI,DATA_PTR ; load DATA_PTR into SI for use
LODSW ; fetch the word pointed to by DATA_PTR
Alternatively, you can address specific unnamed memory locations
by enclosing the location value in square brackets; for example,
MOV AL,[02000] ; load contents of location 02000 into AL
6-2
Note that A86 discerned from context (loading into AL) that a
BYTE at 02000 was intended. Sometimes this is impossible, and
you must specify byte or word:
INC B[02000] ; increment the byte at location 02000
MOV W[02000],0 ; set the WORD at location 02000 to zero
INDEXED MEMORY: The 86 supports the use of certain registers as
base pointers and index registers into memory. BX and BP are the
base registers; SI and DI are the index registers. You may
combine at most one base register, at most one index register,
and a constant number into a run time pointer that determines the
location of the effective address memory to be used in the
instruction. These can be given explicitly, by enclosing the
index registers in brackets:
MOV AX,[BX]
MOV CX,W[SI+17]
MOV AX,[BX+SI+5]
MOV AX,[BX][SI]5 ; another way to write the same instr.
Or, indexing can be accomplished by declaring variables in a
based structure (see the STRUC directive in Chapter 9):
STRUC [BP] ; NOTE: based structures are unique to A86!
BP_SAVE DW ? ; BP_SAVE is a word at [BP]
RET_ADDR DW ? ; RET_ADDR is a word at [BP+2]
PARM1 DW ? ; PARM1 is a word at [BP+4]
PARM2 DW ? ; PARM2 is a word at [BP+6]
ENDS ; end of structure
INC PARM1 ; equivalent to INC W[BP+4]
Finally, indexing can be done by mixing explicit components with
declared ones:
TABLE DB 4,2,1,3,5
MOV AL,TABLE[BX] ; load byte number BX of TABLE
The 386 processor also supports indexing using any of the eight
32-bit general registers. This type of indexing is of limited
use for memory referencing from real-mode programs (most programs
running under DOS), since offsets greater than 64K are disallowed
in real mode (you will get a General Protection Fault if you try
it). 32-bit indexing is, however, useful in conjunction with the
LEA instruction, giving an extremely powerful register arithmetic
instruction. For example, LEA ECX,[EAX+2*EBX+17000] performs two
additions and a multiplication, all in a single machine
instruction. Since no memory accessed is actually attempted,
this kind of LEA usage is allowed in real-mode DOS programs.
At the time of this writing, my A386 assembler does not yet
support 32-bit indexing; I hope to add it soon. If you have A386
on your registered A86+D86 disk, see the A386.DOC file for the
latest implementation news.
6-3
In 32-bit indexing, you may use one or two of any of the 32-bit
general registers. You may also scale one of the indexing
registers, by multiplying it by 2, 4, or 8. You may also add or
subtract a constant of any size up to a doubleword capacity to
the indexed quantity. If you use the same register twice and
scale one of the instances of that register, you get, in effect,
an odd-number scaling (3, 5, or 9) of that register; e.g., A386
will allow LEA EAX,[9*EBX] as an abbreviation for LEA
EAX,[8*EBX+EBX].
Due to coding restrictions, the ESP register can be used only
once within an indexed quantity, and cannot be scaled.
Some more examples of 32-bit indexing are:
XCHG DX,[EAX]
MOV AL,[EAX+EBX]
ADD EBX,[ESI+8*ECX+3391811]
LEA ECX,[4*EBX-7]
Segmentation and Effective Addresses
The 86 family has four segment registers, CS, DS, ES, and SS,
used to address memory. The 386 and later processors add two
more segment registers FS and GS. Each segment register points
to 64K bytes of memory within the 1-megabyte memory space of the
86. (The start of the 64K is calculated by multiplying the
segment register value by 16; i.e., by shifting the value left by
one hex digit.) If your program's code, data and stack areas can
all fit in the same 64K bytes, you can leave all the segment
registers set to the same value. In that case, you won't have to
think about segment registers: no matter which one is used to
address memory, you'll still get the same 64K. If your program
needs more than 64K, you must point one or more segment registers
to other parts of the memory space. In this case, you must take
care that your memory references use the segment registers you
intended.
Each effective address memory access has a default segment
register, to be used if you do not explicitly specify which
segment register you wish. For most effective addresses, the
default segment register is DS. The exceptions are those
effective addresses that use the BP register for indexing. All
BP-indexed memory references have a default of SS. (This is
because BP is intended to be used for addressing local variables,
stored on the stack.)
6-4
If you wish your memory access to use a different segment
register, you provide a segment override byte before the
instruction containing the effective address operand. In the A86
language, you code the override by giving the name of the segment
register you wish before the instruction mnemonic. For example,
suppose you want to load the AL register with the memory byte
pointed to by BX. If you code MOV AL,[BX], the DS register will
be used to determine which 64K segment BX is pointing to. If you
want the byte to come from the CS-segment instead, you code CS
MOV AL,[BX]. Be aware that the segment override byte has effect
only upon the single instruction that follows it. If you hav